package classifier;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

import rcscene.Action;
import rcscene.ObjectWeights;
import sceneInfo.FuzzyFramework;
import sceneInfo.FuzzySceneLib;
import weka.core.AttributeStats;
import weka.core.Instances;
import weka.core.converters.ArffSaver;
import weka.filters.supervised.instance.Resample;
import weka.filters.unsupervised.attribute.Remove;
import sceneInfo.*;
import weka.filters.*;

public class combinTrainingSet {
	// static void main (String[] args)
	public  static void main (String[] args) throws Exception{
		/*Take x number of .lsf files and convert into instances. Put them all into one big instance. Resample the data as expected
		 * rest 
		 */

		if (args.length !=1) {
			System.err.println( "Error : this main method requires a configuration file listing the log files and sampling parameters: \n" +
					"usage : java combinTrainingSet [config file name]\n"+
					"The parameter file should contain:\n"+
					"LogFiles logfile1.lsf logfile2.lsf (a list of at least 1 logfile, on the same line, separated by spaces) \n"+
					"OutputFile [outputfilename] the file to output the re-sampled training set in arff format\n"+
					"AngleParameters [list of angle parameters] (optional, see code for default values)\n"+
					"Distanceparameters [list of distance parameters](optional, see code for default values)\n"+
					"NumberOfKick [expected number of kick instances in output file] (optional, default : use all)\n"+
					"NumberOfDash [expected number of dash instances in output file] (optional, def :use all)\n"+
			"NumberOfTurn [expected number of turn instances in output file] (optional, def :use all)\n");
			throw new Exception("Aborted : missing config file.");
		}
		//first argument should be config file
		String configfile = args[0];


		BufferedReader in = new BufferedReader(new FileReader(configfile));
		String str;
		StringTokenizer m_tokenizer;

		///////////////////////////////////////

		/* list of log files to read from config file*/
		List<String> inputLogFiles = new ArrayList<String>();
		String outFile = "resample.arff";
		int resampleKick = -1;
		int resampleDash = -1;
		int resampleTurn = -1;

		List<Float> angleParameters = new ArrayList<Float>(); // angle parameters : with the List type we can create the list without knowing ahead of time how many we will have
		List<Float> distanceParameters = new ArrayList<Float>(); // distance parameters
		//we have default discretization parameters.
		float [] arrayAngleParam =new float[1];
		float [] arrayDistanceParam = new float[1];

		//READING FROM CONFIG FILE/////////////
		while ((str = in.readLine()) != null) //reading lines from config file to get parameter list
		{
			str.trim();
			if (str.startsWith("#")) continue;//comment in config file

			//tokenize line.
			m_tokenizer = new StringTokenizer(str);

			/////////////////////////////////////////////
			// get parameters from line in config file:
			/////////////////////////////////////////////

			//first token is parameter name :
			String paramname = m_tokenizer.nextToken();


			if (paramname.startsWith("LogFiles")) // list of log files 
			{

				//read a list of files separated by spaces... as many as there are.
				while (m_tokenizer.hasMoreTokens()){
					inputLogFiles.add(m_tokenizer.nextToken());
				}

			} else if (paramname.startsWith("OutputFile")) {
				outFile = m_tokenizer.nextToken();


			} else if (paramname.startsWith("AngleParam")) {
				//read the angle parameters : there should be nothing else on the line
				while (m_tokenizer.hasMoreTokens()){
					try {
						angleParameters.add(Float.parseFloat(m_tokenizer.nextToken()));
					}
					catch (Exception e){
						System.err.println("reading dist parameters: Exception caught!! " + e.toString());	
					}
				}
			} else if (paramname.startsWith("DistanceParam")) {
				while (m_tokenizer.hasMoreTokens()){
					try {
						distanceParameters.add(Float.parseFloat(m_tokenizer.nextToken()));
					}
					catch (Exception e){
						System.err.println("reading dist parameters: Exception caught!! " + e.toString());	
					}
				}
			}else if (paramname.startsWith("NumberOfKick")) {
				resampleKick = Integer.parseInt(m_tokenizer.nextToken());
				
				System.out.println(" number of kick"+ resampleKick);
			}else if (paramname.startsWith("NumberOfDash")) {
				resampleDash = Integer.parseInt(m_tokenizer.nextToken());
				System.out.println(" number of kick"+ resampleKick);
			}else if (paramname.startsWith("NumberOfTurn")) {
				resampleTurn = Integer.parseInt(m_tokenizer.nextToken());
				System.out.println(" number of turn :"+ resampleTurn);
			}


			
			if (angleParameters.size()==0||distanceParameters.size()==0){
				System.out.println("Discretization parameters missing, using default values");
				arrayAngleParam = new float [] {-88.0f, -27.0f, -9.0f, 0.0f,3.0f, 13.0f, 29.0f, 88.0f};
				arrayDistanceParam = new float [] {1.1f, 4.1f, 22.2f, 48.4f,73.0f};
			} else {
				arrayAngleParam = new float[angleParameters.size()];
				for (int i = 0; i<angleParameters.size();i++){
					arrayAngleParam[i]=angleParameters.get(i).floatValue(); //get Float and convert to float
				}
				Arrays.sort(arrayAngleParam); //sort the parameters

				arrayDistanceParam = new float[distanceParameters.size()];
				for (int i = 0; i<distanceParameters.size();i++){
					arrayDistanceParam[i]=distanceParameters.get(i).floatValue(); //get Float and convert to float
				}
				Arrays.sort(arrayDistanceParam); //sort the parameters

			}
		}
		if(inputLogFiles.size()==0){
			throw new Exception("Error : no log files provided");
		}

		FuzzySceneLib sceneLib = new FuzzySceneLib();

		FuzzyFramework ff1= new FuzzyFramework(arrayAngleParam,arrayDistanceParam);
		sceneLib.setFramework(ff1);


		//read all the files
		for (String logFileName : inputLogFiles){
			System.out.println(" parsing file :"+logFileName);
			sceneLib.parseLog(logFileName);}
		//System.out.println(" lib has scenes :" +first.getSceneList().size());
		//now sceneLib contains ALL the scenes from ALL the log files.
		//discretize all the scenes...
		sceneLib.discretizeThis(ff1);
		Instances firstLogfile = sceneLib.toCompleteWekaDataset();

		int numAttri = firstLogfile.numAttributes();
		firstLogfile.sort(numAttri-3);
		AttributeStats stats = firstLogfile.attributeStats(numAttri-3);
		int[] counts = stats.nominalCounts;

		System.out.println("count action kick is  " + counts[Action.ACTION_KICK]);
		System.out.println("count action dash is  " + counts[Action.ACTION_DASH]);
		System.out.println("count action turn is  " + counts[Action.ACTION_TURN]);
		//System.out.println("number of firstLogfile data instances is : " +firstLogfile.numInstances());

		//separate the datasets
		Instances dashData = new Instances (firstLogfile, counts[Action.ACTION_NONE], 
				counts[Action.ACTION_DASH]);

		Instances kickData = new Instances (firstLogfile, counts[Action.ACTION_DASH] + 
				counts[Action.ACTION_NONE], 
				counts[Action.ACTION_KICK]);


		Instances turnData = new Instances (firstLogfile, counts[Action.ACTION_NONE] +
				counts[ Action.ACTION_DASH]+
				counts[Action.ACTION_KICK]+
				counts[Action.ACTION_TURNNECK], 
				counts[Action.ACTION_TURN]);

		//System.out.println("number of turn data instances is : " +turnData.numInstances());

		Resample dashResampler = new Resample();
		dashData.setClassIndex(dashData.numAttributes()-3);
		dashResampler.setInputFormat(dashData);

		//calculate the resampling percentage :

		double samplingpct = 100; //default
		if(resampleDash !=-1){
			samplingpct = (resampleDash *100 )/ counts[Action.ACTION_DASH];
		}
		dashResampler.setSampleSizePercent(samplingpct);
		Instances dashDataFiltered = Filter.useFilter(dashData, dashResampler);
		System.out.println("number of dash data filtered is : " + dashDataFiltered.numInstances());

		Resample turnResampler = new Resample();
		turnData.setClassIndex(turnData.numAttributes()-3);
		turnResampler.setInputFormat(turnData);

		samplingpct = 100; //default
		if(resampleTurn !=-1){
			samplingpct = (resampleTurn *100 )/ counts[Action.ACTION_TURN];
		}
		turnResampler.setSampleSizePercent(samplingpct);
		Instances turnDataFiltered = Filter.useFilter(turnData, turnResampler);
		System.out.println("number of turn data filtered is : " + turnDataFiltered.numInstances());


		Resample kickResampler = new Resample();
		kickData.setClassIndex(kickData.numAttributes()-3);
		kickResampler.setInputFormat(kickData);

		samplingpct = 100; //default
		if(resampleKick !=-1){
			samplingpct = (resampleKick *100 )/ counts[Action.ACTION_KICK];
		}
		kickResampler.setSampleSizePercent(samplingpct);

		Instances kickDataFiltered = Filter.useFilter(kickData, kickResampler);
		System.out.println("number of kick data filtered is : " + kickDataFiltered.numInstances());

		//add all resampled data to the dash collection
		for (int j =0;j< turnDataFiltered.numInstances();j++){
			dashDataFiltered.add( turnDataFiltered.instance(j));

		}
		for (int j =0;j< kickDataFiltered.numInstances();j++){
			dashDataFiltered.add( kickDataFiltered.instance(j));

		}

		System.out.println("Total number of instances is : " +dashDataFiltered.numInstances());

		//output arff
		File sceneLibFile = new File(outFile);
		BufferedWriter bfw = new BufferedWriter(new FileWriter(sceneLibFile));

		bfw.write(dashDataFiltered.toString());
		bfw.flush();
		bfw.close();

	}

}
